home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Utilities / Unix / skey / src / skeylogin.c < prev    next >
C/C++ Source or Header  |  1993-11-08  |  9KB  |  438 lines

  1. /* S/KEY v1.1b (skeylogin.c)
  2.  *
  3.  * Authors:
  4.  *          Neil M. Haller <nmh@thumper.bellcore.com>
  5.  *          Philip R. Karn <karn@chicago.qualcomm.com>
  6.  *          John S. Walden <jsw@thumper.bellcore.com>
  7.  *          Scott Chasin <chasin@crimelab.com>
  8.  *
  9.  * S/KEY verification check, lookups, and authentication.
  10.  */
  11.  
  12. #include <sys/param.h>
  13. #ifdef    QUOTA
  14. #include <sys/quota.h>
  15. #endif
  16. #include <sys/stat.h>
  17. #include <sys/time.h>
  18. #include <sys/timeb.h>
  19. #include <sys/resource.h>
  20.  
  21.  
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <sys/types.h>
  25. #include <sys/stat.h>
  26. #include <time.h>
  27. #include <errno.h>
  28. #include "skey.h"
  29.  
  30. #define    KEYFILE    "/etc/skeykeys"
  31.  
  32. char *skipspace();
  33. int skeylookup __ARGS((struct skey *mp,char *name));
  34.  
  35.  
  36. /* Issue a skey challenge for user 'name'. If successful,
  37.  * fill in the caller's skey structure and return 0. If unsuccessful
  38.  * (e.g., if name is unknown) return -1.
  39.  *
  40.  * The file read/write pointer is left at the start of the
  41.  * record.
  42.  */
  43. int
  44. getskeyprompt(mp,name,prompt)
  45. struct skey *mp;
  46. char *name;
  47. char *prompt;
  48. {
  49.     int rval;
  50.  
  51.     sevenbit(name);
  52.     rval = skeylookup(mp,name);
  53.     strcpy(prompt,"s/key 55 latour1\n");
  54.     switch(rval){
  55.     case -1:    /* File error */
  56.         return -1;
  57.     case 0:        /* Lookup succeeded, return challenge */
  58.         sprintf(prompt,"s/key %d %s\n",mp->n - 1,mp->seed);
  59.         return 0;
  60.     case 1:        /* User not found */
  61.         fclose(mp->keyfile);
  62.         return -1;
  63.     }
  64.     return -1;    /* Can't happen */
  65. }    
  66. /* Return  a skey challenge string for user 'name'. If successful,
  67.  * fill in the caller's skey structure and return 0. If unsuccessful
  68.  * (e.g., if name is unknown) return -1.
  69.  *
  70.  * The file read/write pointer is left at the start of the
  71.  * record.
  72.  */
  73. int
  74. skeychallenge(mp,name, ss)
  75. struct skey *mp;
  76. char *name;
  77. char *ss;
  78. {
  79.     int rval;
  80.  
  81.     rval = skeylookup(mp,name);
  82.     switch(rval){
  83.     case -1:    /* File error */
  84.         return -1;
  85.     case 0:        /* Lookup succeeded, issue challenge */
  86.                 sprintf(ss, "s/key %d %s",mp->n - 1,mp->seed);
  87.         return 0;
  88.     case 1:        /* User not found */
  89.         fclose(mp->keyfile);
  90.         return -1;
  91.     }
  92.     return -1;    /* Can't happen */
  93. }    
  94.  
  95. /* Find an entry in the One-time Password database.
  96.  * Return codes:
  97.  * -1: error in opening database
  98.  *  0: entry found, file R/W pointer positioned at beginning of record
  99.  *  1: entry not found, file R/W pointer positioned at EOF
  100.  */
  101. int
  102. skeylookup(mp,name)
  103. struct skey *mp;
  104. char *name;
  105. {
  106.     int found;
  107.     int len;
  108.     long recstart;
  109.     char *cp;
  110.     struct stat statbuf;
  111.  
  112.     /* See if the KEYFILE exists, and create it if not */
  113.     if(stat(KEYFILE,&statbuf) == -1 && errno == ENOENT){
  114.         mp->keyfile = fopen(KEYFILE,"w+");
  115.     } else {
  116.         /* Otherwise open normally for update */
  117.         mp->keyfile = fopen(KEYFILE,"r+");
  118.     }
  119.     if(mp->keyfile == NULL)
  120.         return -1;
  121.  
  122.     /* Look up user name in database */
  123.     len = strlen(name);
  124.     if( len > 8 ) len = 8;        /*  Added 8/2/91  -  nmh */
  125.     found = 0;
  126.     while(!feof(mp->keyfile)){
  127.         recstart = ftell(mp->keyfile);
  128.         mp->recstart = recstart;
  129.         if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
  130.             break;
  131.         }
  132.         rip(mp->buf);
  133.         if(mp->buf[0] == '#')
  134.             continue;    /* Comment */
  135.         if((mp->logname = strtok(mp->buf," \t")) == NULL)
  136.             continue;
  137.         if((cp = strtok(NULL," \t")) == NULL)
  138.             continue;
  139.         mp->n = atoi(cp);
  140.         if((mp->seed = strtok(NULL," \t")) == NULL)
  141.             continue;
  142.         if((mp->val = strtok(NULL," \t")) == NULL)
  143.             continue;
  144.         if(strlen(mp->logname) == len
  145.          && strncmp(mp->logname,name,len) == 0){
  146.             found = 1;
  147.             break;
  148.         }
  149.     }
  150.     if(found){
  151.         fseek(mp->keyfile,recstart,0);
  152.         return 0;
  153.     } else
  154.         return 1;
  155. }
  156. /* Verify response to a s/key challenge.
  157.  *
  158.  * Return codes:
  159.  * -1: Error of some sort; database unchanged
  160.  *  0:  Verify successful, database updated
  161.  *  1:  Verify failed, database unchanged
  162.  *
  163.  * The database file is always closed by this call.
  164.  */
  165. int
  166. skeyverify(mp,response)
  167. struct skey *mp;
  168. char *response;
  169. {
  170.  struct timeval startval;
  171.  struct timeval endval;
  172. long microsec;
  173.     char key[8];
  174.     char fkey[8];
  175.     char filekey[8];
  176.     time_t now;
  177.     struct tm *tm;
  178.     char tbuf[27],buf[60];
  179.     char me[80];
  180.     int rval;
  181.     char *cp;
  182.  
  183.     time(&now);
  184.     tm = localtime(&now);
  185.     strftime(tbuf, sizeof(tbuf), " %b %d,%Y %T", tm);
  186.  
  187.     if(response == NULL){
  188.         fclose(mp->keyfile);
  189.         return -1;
  190.     }
  191.     rip (response);
  192.  
  193.     /* Convert response to binary */
  194.     if(etob(key, response) != 1 && atob8(key, response) != 0){
  195.         /* Neither english words or ascii hex */
  196.         fclose(mp->keyfile);
  197.         return -1;
  198.     }
  199.  
  200.     /* Compute fkey = f(key) */
  201.     memcpy(fkey,key,sizeof(key));
  202.         fflush (stdout);
  203.  
  204.     f(fkey);
  205.     /* in order to make the window of update as short as possible
  206.            we must do the comparison here and if OK write it back
  207.            other wise the same password can be used twice to get in
  208.          to the system
  209.     */
  210.  
  211.     setpriority(PRIO_PROCESS, 0, -4);
  212.  
  213.     /* reread the file record NOW*/
  214.  
  215.     fseek(mp->keyfile,mp->recstart,0);
  216.     if(fgets(mp->buf,sizeof(mp->buf),mp->keyfile) != mp->buf){
  217.         setpriority(PRIO_PROCESS, 0, 0);
  218.         fclose(mp->keyfile);
  219.         return -1;
  220.     }
  221.     rip(mp->buf);
  222.     mp->logname = strtok(mp->buf," \t");
  223.     cp = strtok(NULL," \t") ;
  224.     mp->seed = strtok(NULL," \t");
  225.     mp->val = strtok(NULL," \t");
  226.     /* And convert file value to hex for comparison */
  227.     atob8(filekey,mp->val);
  228.  
  229.     /* Do actual comparison */
  230.         fflush (stdout);
  231.  
  232.     if(memcmp(filekey,fkey,8) != 0){
  233.         /* Wrong response */
  234.         setpriority(PRIO_PROCESS, 0, 0);
  235.         fclose(mp->keyfile);
  236.         return 1;
  237.     }
  238.  
  239.     /* Update key in database by overwriting entire record. Note
  240.      * that we must write exactly the same number of bytes as in
  241.      * the original record (note fixed width field for N)
  242.      */
  243.     btoa8(mp->val,key);
  244.     mp->n--;
  245.     fseek(mp->keyfile,mp->recstart,0);
  246.     fprintf(mp->keyfile,"%s %04d %-16s %s %-21s\n",mp->logname,mp->n,mp->seed,
  247.      mp->val, tbuf);
  248.  
  249.     fclose(mp->keyfile);
  250.     
  251.     setpriority(PRIO_PROCESS, 0, 0);
  252.     return 0;
  253. }
  254.  
  255.  
  256. /* Convert 8-byte hex-ascii string to binary array
  257.  * Returns 0 on success, -1 on error
  258.  */
  259. atob8(out,in)
  260. register char *out,*in;
  261. {
  262.     register int i;
  263.     register int val;
  264.  
  265.     if (in == NULL || out == NULL)
  266.         return -1;
  267.  
  268.     for(i=0;i<8;i++){
  269.         if((in = skipspace(in)) == NULL)
  270.             return -1;
  271.         if((val = htoi(*in++)) == -1)
  272.             return -1;
  273.         *out = val << 4;
  274.  
  275.         if((in = skipspace(in)) == NULL)
  276.             return -1;
  277.         if((val = htoi(*in++)) == -1)
  278.             return -1;
  279.         *out++ |= val;
  280.     }
  281.     return 0;
  282. }
  283.  
  284. char *
  285. skipspace(cp)
  286. register char *cp;
  287. {
  288.     while(*cp == ' ' || *cp == '\t')
  289.         cp++;
  290.  
  291.     if(*cp == '\0')
  292.         return NULL;
  293.     else
  294.         return cp;
  295. }
  296.  
  297. /* Convert 8-byte binary array to hex-ascii string */
  298. int
  299. btoa8(out,in)
  300. register char *out,*in;
  301. {
  302.     register int i;
  303.  
  304.     if(in == NULL || out == NULL)
  305.         return -1;
  306.  
  307.     for(i=0;i<8;i++){
  308.         sprintf(out,"%02x",*in++ & 0xff);
  309.         out += 2;
  310.     }
  311.     return 0;
  312. }
  313.  
  314.  
  315. /* Convert hex digit to binary integer */
  316. int
  317. htoi(c)
  318. register char c;
  319. {
  320.     if('0' <= c && c <= '9')
  321.         return c - '0';
  322.     if('a' <= c && c <= 'f')
  323.         return 10 + c - 'a';
  324.     if('A' <= c && c <= 'F')
  325.         return 10 + c - 'A';
  326.     return -1;
  327. }
  328.  
  329. /*
  330.  * skey_haskey ()
  331.  *
  332.  * Returns: 1 user doesnt exist, -1 fle error, 0 user exists.
  333.  *
  334.  */
  335.  
  336. skey_haskey (username)
  337.   char *username;
  338. {
  339.   int i;
  340.   struct skey skey;
  341.  
  342.   return (skeylookup (&skey, username));
  343. }
  344.  
  345. /*
  346.  * skey_keyinfo ()
  347.  *
  348.  * Returns the current sequence number and
  349.  * seed for the passed user.
  350.  *
  351.  */
  352. char *skey_keyinfo (username)
  353.   char *username;
  354. {
  355.   int i;
  356.   char str [50];
  357.  
  358.   struct skey skey;
  359.  
  360.   i = skeychallenge (&skey, username, str);
  361.  
  362.   if (i == -2)
  363.      return 0;
  364.  
  365.   return str;
  366. }
  367.  
  368. /*
  369.  * skey_passcheck ()
  370.  *
  371.  * Check to see if answer is the correct one to the current
  372.  * challenge.
  373.  *
  374.  * Returns: 0 success, -1 failure
  375.  *
  376.  */
  377.  
  378. skey_passcheck (username, passwd)
  379.   char *username, *passwd;
  380. {
  381.   int i;
  382.   struct skey skey;
  383.  
  384.   i = skeylookup (&skey, username);
  385.  
  386.   if (i == -1 || i == 1)
  387.       return -1;
  388.  
  389.   if (skeyverify (&skey, passwd) == 0)
  390.       return skey.n;
  391.  
  392.   return -1;
  393. }
  394.  
  395. /*
  396.  * skey_authenticate ()
  397.  *
  398.  * Used when calling program will allow input of the user's
  399.  * response to the challenge.
  400.  *
  401.  * Returns: 0 success, -1 failure
  402.  *
  403.  */
  404.  
  405. skey_authenticate (username)
  406.   char *username;
  407. {
  408.   int i;
  409.   char pbuf [256], skeyprompt [50];
  410.   struct skey skey;
  411.  
  412.   /* Attempt a S/Key challenge */
  413.   i = skeychallenge (&skey, username, skeyprompt);
  414.  
  415.   if (i == -2)
  416.     return 0;
  417.  
  418.   printf ("[%s]\n", skeyprompt);
  419.   fflush (stdout);
  420.  
  421.   printf ("Response: ");
  422.   readpass (pbuf, sizeof (pbuf));
  423.   rip (pbuf);
  424.  
  425.   /* Is it a valid response? */
  426.   if (i == 0 && skeyverify (&skey, pbuf) == 0)
  427.   {
  428.     if (skey.n < 5)
  429.     {
  430.       printf ("\nWarning! Key initialization needed soon.  ");
  431.       printf ("(%d logins left)\n", skey.n);
  432.     }
  433.     return 0;
  434.   }
  435.   return -1;
  436. }
  437.  
  438.